package com.sziit.se.highconcurrency.order.application.controller;

import com.alibaba.fastjson.JSON;
import com.sziit.se.highconcurrency.common.annotation.IgnoreCheck;
import com.sziit.se.highconcurrency.common.result.DataResult;
import com.sziit.se.highconcurrency.common.result.Result;
import com.sziit.se.highconcurrency.common.result.ResultUtil;
import com.sziit.se.highconcurrency.order.application.entity.*;
import com.sziit.se.highconcurrency.order.application.feignclient.ProductFeign;
import com.sziit.se.highconcurrency.order.application.feignclient.UserFeign;
import com.sziit.se.highconcurrency.order.application.service.IOrderDetailService;
import com.sziit.se.highconcurrency.order.application.service.IOrderService;
import freemarker.debug.impl.RmiDebuggedEnvironmentImpl_Stub;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.FutureTask;

@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/order")
public class OrderDetailControllerV2 {
    private final IOrderDetailService orderDetailService;

    private final IOrderService orderService;

    private final ProductFeign productFeign;

    private final UserFeign userFeign;

    private final Object lock = new Object();


    @IgnoreCheck
    @GetMapping("/order/query-by-id")
    public Result getOrderInfo(@RequestParam(value = "order_id") String orderId) throws InterruptedException {
        Order order = orderService.getOneData(orderId);
        List<OrderDetail> orderDetails = orderDetailService.getProductByOrderId(orderId);
        OnlyOrderInfo orderInfo = new OnlyOrderInfo();
        orderInfo.setOrderDetailList(orderDetails);
        orderInfo.setUser_id(order.getUserId());

        return ResultUtil.data(orderInfo);
    }


    @GetMapping("/order/detail-v2")
    public Result getOrderDetail(@RequestParam(value = "order_id") String orderId) throws InterruptedException {
        log.info("enter api /order/detail/v2");
        Order order = orderService.getOneData(orderId);
        List<OrderDetail> orderDetails = orderDetailService.getProductByOrderId(orderId);


        List<FutureTask> futureTaskList = new ArrayList<>();
        for (OrderDetail orderDetail : orderDetails) {
            String productId = orderDetail.getProductId();

            //定义一个futureTask，属于runnable类型，可作为线程创建的参数。然后异步执行后，可通过futureTask.get()获取结果
            FutureTask<DataResult<Product>> futureTask = new FutureTask(()-> productFeign.getProductById(productId));
            //将futureTask维护一个list，后续通过list获取futureTask和每个异步任务执行结果
            futureTaskList.add(futureTask);
            Thread thread = new Thread(futureTask);
            thread.start();

        }

        //从user微服务获取用户信息，远程调用
        FutureTask<DataResult<User>> userFutureTask = new FutureTask(()->{
            return userFeign.getUserById(order.getUserId());
        });
        Thread userThread = new Thread(userFutureTask);
        userThread.start();

        //从product微服务查询product信息，并组装成List<ProductDetail>
        List<ProductDetail> productDetailList = new ArrayList<>();
        for (FutureTask futureTask : futureTaskList) {
            DataResult productResult = null;
            try {
                log.info("future get product result");
                productResult = (DataResult) futureTask.get();
            } catch (Exception e) {
                e.printStackTrace();
            }

            LinkedHashMap productHashMap = (LinkedHashMap) productResult.getData();
            Product product = JSON.parseObject(JSON.toJSONString(productHashMap), Product.class);
            log.info("print product is" + product.getProductName());

            ProductDetail productDetail = new ProductDetail();
            productDetail.setProductName(product.getProductName());
            productDetail.setPrice(product.getPrice());
            productDetail.setProductId(product.getProductId());
            productDetailList.add(productDetail);
        }


        DataResult userResult = null;
        try {
            userResult = (DataResult) userFutureTask.get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        LinkedHashMap userHashMap = (LinkedHashMap) userResult.getData();
        User userInfo = JSON.parseObject(JSON.toJSONString(userHashMap), User.class);

        //将购买的产品信息和用户信息组装最后的响应体
        OrderDetailRsp orderDetailRsp = new OrderDetailRsp();
        orderDetailRsp.setProductDetailList(productDetailList);
        orderDetailRsp.setUserName(userInfo.getUserName());
        orderDetailRsp.setPhone(userInfo.getPhone());
        orderDetailRsp.setOrderId(order.getOrderId());
        orderDetailRsp.setUserId(userInfo.getUserId());

        return ResultUtil.data(orderDetailRsp);
    }


    @GetMapping("/order/detail/flow-control")
    public Result getOrderDetailWithFlowControl(@RequestParam(value = "order_id") String orderId) throws InterruptedException {
        log.info("enter api /order/detail/flow-control");
        Order order = orderService.getOneData(orderId);
        List<OrderDetail> orderDetails = orderDetailService.getProductByOrderId(orderId);


        List<FutureTask> futureTaskList = new ArrayList<>();
        for (OrderDetail orderDetail : orderDetails) {
            String productId = orderDetail.getProductId();

            //定义一个futureTask，属于runnable类型，可作为线程创建的参数。然后异步执行后，可通过futureTask.get()获取结果
            FutureTask<DataResult<Product>> futureTask = new FutureTask(()-> productFeign.getProductById(productId));
            //将futureTask维护一个list，后续通过list获取futureTask和每个异步任务执行结果
            futureTaskList.add(futureTask);
            Thread thread = new Thread(futureTask);
            thread.start();

        }

        //从user微服务获取用户信息，远程调用
        FutureTask<DataResult<User>> userFutureTask = new FutureTask(()->{
            return userFeign.getUserById(order.getUserId());
        });
        Thread userThread = new Thread(userFutureTask);
        userThread.start();

        //从product微服务查询product信息，并组装成List<ProductDetail>
        List<ProductDetail> productDetailList = new ArrayList<>();
        for (FutureTask futureTask : futureTaskList) {
            DataResult productResult = null;
            try {
                log.info("future get product result");
                productResult = (DataResult) futureTask.get();
            } catch (Exception e) {
                e.printStackTrace();
            }

            LinkedHashMap productHashMap = (LinkedHashMap) productResult.getData();
            Product product = JSON.parseObject(JSON.toJSONString(productHashMap), Product.class);
            log.info("print product is" + product.getProductName());

            ProductDetail productDetail = new ProductDetail();
            productDetail.setProductName(product.getProductName());
            productDetail.setPrice(product.getPrice());
            productDetail.setProductId(product.getProductId());
            productDetailList.add(productDetail);
        }


        DataResult userResult = null;
        try {
            userResult = (DataResult) userFutureTask.get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        LinkedHashMap userHashMap = (LinkedHashMap) userResult.getData();
        User userInfo = JSON.parseObject(JSON.toJSONString(userHashMap), User.class);

        //将购买的产品信息和用户信息组装最后的响应体
        OrderDetailRsp orderDetailRsp = new OrderDetailRsp();
        orderDetailRsp.setProductDetailList(productDetailList);
        orderDetailRsp.setUserName(userInfo.getUserName());
        orderDetailRsp.setPhone(userInfo.getPhone());
        orderDetailRsp.setOrderId(order.getOrderId());
        orderDetailRsp.setUserId(userInfo.getUserId());

        return ResultUtil.data(orderDetailRsp);
    }

    @IgnoreCheck
    @PostMapping(value = "/order-v2")
    @Transactional
    public Result createOrder(@RequestBody CreateOrderReq createOrderReq) throws Exception {

        String orderId = UUID.randomUUID().toString();
        List<ProductDetail> productDetails = createOrderReq.getProductDetailList();

        //根据订单中的每个商品购买数量，更新库存信息并将订单的详情保存在order_detail表中
        List<OrderDetail> orderDetails = new ArrayList<>();
        synchronized (lock) {
            for (ProductDetail productDetail : productDetails) {
                String productId = productDetail.getProductId();
                DataResult productResult = productFeign.getProductById(productId);
                LinkedHashMap productHashMap = (LinkedHashMap) productResult.getData();
                Product product = JSON.parseObject(JSON.toJSONString(productHashMap), Product.class);

                if (null == product) {
                    log.info("product is not on sail");
                    throw new Exception("该商品不存在");
                }
                if (productDetail.getAmount() > product.getInventory()) {
                    log.info("Inventory is lack");
                    throw new Exception("库存不足，请减少购买数量");
                }
            }


            for (ProductDetail productDetail : productDetails) {
                String productId = productDetail.getProductId();
                DataResult productResult = productFeign.getProductById(productId);
                LinkedHashMap productHashMap = (LinkedHashMap) productResult.getData();
                Product product = JSON.parseObject(JSON.toJSONString(productHashMap), Product.class);
                product.setInventory(product.getInventory()-productDetail.getAmount());
                productFeign.updateProductById(product);
            }
        }

        for (ProductDetail productDetail : productDetails) {
            String productId = productDetail.getProductId();
            orderDetailService.insertOrderDetail(orderId, productId, productDetail.getAmount());
            //组装orderDetails，作为返回值一部分返回
            OrderDetail orderDetail = new OrderDetail();
            orderDetail.setOrderId(orderId);
            orderDetail.setProductId(productId);
            orderDetail.setAmount(productDetail.getAmount());
            orderDetails.add(orderDetail);
        }
        //订单信息存入订单表中
        Boolean orderSuccess = orderService.insertOrder(orderId, createOrderReq.getUserId());
        OnlyOrderInfo orderInfo = new OnlyOrderInfo();
        orderInfo.setOrderDetailList(orderDetails);
        orderInfo.setUser_id(createOrderReq.getUserId());
        return ResultUtil.data(orderInfo);
    }


}
